package auths

import (
	"bytes"
	"context"
	"encoding/json"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/errors"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/https"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/resultcode"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/results"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	"io/ioutil"
	"net/http"
)

var (
	// 认证方式, server
	AUTH_TYPE_SERVER = "server"
	// 认证方式, istio
	AUTH_TYPE_ISTIO = "istio"
	// 认证成功返回
	AUTH_SUCCESS_RESP = "1"
	// 认证失败返回
	AUTH_FAIL_RESP = "0"
)

var USER_INFO_KEY = "k_user_info"

// rbac权限验证
// authType:认证方式，支持 server 和 istio
// authAddress: 认证地址, authType为server时候使用
// publicKey: 公钥
func RbacAuthMiddle(viper *viper.Viper) gin.HandlerFunc {
	return func(c *gin.Context) {
		authType := viper.GetString("auth.type")
		publicKey := viper.GetString("rbac.publicKey")
		if authType == AUTH_TYPE_SERVER {
			authAddress := viper.GetString("auth.address")
			valid := serverAuthValid(c, authAddress)
			if !valid {
				return
			}
		}
		tokenValue := getToken(c)
		if tokenValue != "" {
			rbacClaim, err := ParseRbac([]byte(publicKey), tokenValue)
			if err != nil {
				c.JSON(https.StatusUnauthorized, results.Err(errors.NewError("token解析失败", resultcode.AUTH_NEED_LOGIN)))
				return
			}
			userInfo := rbacClaim.UserInfo
			newCtx := context.WithValue(c.Request.Context(), USER_INFO_KEY, &userInfo)
			c.Request = c.Request.WithContext(newCtx)
		}
		c.Next()

	}
}

func getToken(c *gin.Context) string {
	tokenValue := c.GetHeader("Authorization")
	return tokenValue
}

// 权限服务验证
func serverAuthValid(c *gin.Context, authAddress string) bool {
	method := c.Request.Method
	body, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		c.JSON(https.StatusInternalServerError, results.Err(errors.NewError("获取请求内容失败", resultcode.AUTH_OTHER_ERROR)))
		return false
	}
	c.Request.Body = ioutil.NopCloser(bytes.NewReader(body))

	//bs, err := ioutil.ReadAll(body)
	if err != nil {
		c.JSON(https.StatusInternalServerError, results.Err(errors.NewError("获取请求内容失败", resultcode.AUTH_OTHER_ERROR)))
		return false
	}
	tokenValue := getToken(c)
	path := c.Request.URL.Path
	m := map[string]string{
		"token":  tokenValue,
		"path":   path,
		"body":   string(body),
		"method": method,
	}
	bs, err := json.Marshal(m)
	if err != nil {
		c.JSON(https.StatusInternalServerError, results.Err(errors.NewError("转换成json失败", resultcode.AUTH_OTHER_ERROR)))
		return false
	}
	response, err := http.Post(authAddress, "application/json", bytes.NewReader(bs))
	if err != nil {
		c.JSON(https.StatusInternalServerError, results.Err(errors.NewError("请求权限服务失败", resultcode.AUTH_OTHER_ERROR)))
		return false
	}
	responseBodyBs, err := ioutil.ReadAll(response.Body)
	if err != nil {
		c.JSON(https.StatusInternalServerError, results.Err(errors.NewError("获取返回内容失败", resultcode.AUTH_OTHER_ERROR)))
		return false
	}
	responseBody := string(responseBodyBs)
	if responseBody == AUTH_SUCCESS_RESP {
		return true
	} else {
		if response.StatusCode == https.StatusUnauthorized {
			c.JSON(response.StatusCode, results.Err(errors.NewError("需要登录", resultcode.AUTH_NEED_LOGIN)))
			return false
		} else if response.StatusCode == https.StatusForbidden {
			c.JSON(response.StatusCode, results.Err(errors.NewError("权限不足", resultcode.AUTH_DENIED)))
			return false
		}
		c.JSON(response.StatusCode, results.Err(errors.NewError("权限不足", resultcode.AUTH_DENIED)))
		return false
	}
}
